package com.taoding.hfhclient.netty_client;

import com.taoding.hfhclient.netty_client.coder.NettyMessageDecoder;
import com.taoding.hfhclient.netty_client.coder.NettyMessageEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author liuxinghong
 * @Description:
 * @date 2019/9/2 000216:15
 */
@Component
@Slf4j
public class NettyClient  {

    public static ChannelFuture future = null;
    private static  NioEventLoopGroup loopGroup = new NioEventLoopGroup();
    public static Bootstrap bootstrap = new Bootstrap();

    /**
     * 启动nettyClient
     */
    @PostConstruct
    public  void startClient() {
        //创建线程组
        bootstrap.channel(NioSocketChannel.class)//客户端通道
                    .group(loopGroup);
        connect();
    }

    /**
     * 连接服务端
     */
    public static void connect(){
        try {

            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    //        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
                    //        pipeline.addLast("decoder", new StringDecoder()); //字符串解码器
                    //        pipeline.addLast("encoder", new StringEncoder()); //字符串编码器
                    //入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式
                    //因为服务端设置的超时时间是5秒，所以设置4秒
                    pipeline.addLast(new IdleStateHandler(0, NettyConfig.NETTY_CLIENT_WRITER_IDLE_TME_TIMES, NettyConfig.NETTY_CLIENT_ALL_IDLE_TME_TIMES, TimeUnit.SECONDS)); //心跳检测机制
                    pipeline.addLast("decoder", new NettyMessageDecoder());  //实体类解码器
                    pipeline.addLast("encoder", new NettyMessageEncoder());  //实体类编码器
                    pipeline.addLast("handler", new ClientHandler()); //业务handler
                }
            });
            future = bootstrap.connect(NettyConfig.NETTY_SERVER_IP, NettyConfig.NETTY_SERVER_PORT).addListener((ChannelFuture futureListener) -> {
                final EventLoop eventLoop = futureListener.channel().eventLoop();
                if (!futureListener.isSuccess()) { //断网或与服务端失去连接时触发此监听
                    log.info("与服务端断开连接~~~~~在" + NettyConfig.NETTY_RECONNECT_TIME + "s之后准备尝试重连,请检查网络连接，网络通畅后自动回复连接!");
                    eventLoop.schedule(() -> connect(), NettyConfig.NETTY_RECONNECT_TIME, TimeUnit.SECONDS);
                }
            }); //todo：使用了连接监听机制后 不可再使用异步操作，否则监听不到结果
            log.info("netty客户端启动中>>>>>>>>>> ");
        } catch (Exception e2) {
            log.error("netty客户端启动失败", e2);
            e2.getStackTrace();
        }
    }


    /**
     * 销毁/关闭客户端
     */
    public static void destroy() {
        try {
            if (null != future) {
                future.channel().close().sync();
            }
           // loopGroup.shutdownGracefully().sync();
        } catch (InterruptedException e) {
            log.error("销毁/关闭netty客戶端失败....");
            e.printStackTrace();
        }
    }



}

